﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using Telerik.Web.Mvc;

namespace Sausage.Web.Domain
{
    public class MaintainQuantityHelper
    {

        public static GridModel<object> Select(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainQuantity(
                        context.MaintainQuantity.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)MaintainDataStateEnum.Confirmed)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainQuantity(
                        context.MaintainQuantity.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)MaintainDataStateEnum.Unsubmit ||
                             item.State == (int)MaintainDataStateEnum.AuditRejected)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> AuditSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainQuantity(context.MaintainQuantity.Where(item=>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)MaintainDataStateEnum.Submitted || 
                     item.State == (int)MaintainDataStateEnum.ConfirmationRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainQuantity(context.MaintainQuantity.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)MaintainDataStateEnum.Audited)
                    , query, isWithChild);
            }
        }

        private static GridModel<object> QueryMaintainQuantity(IQueryable<MaintainQuantity> source, JosnPagingQueryModel query, bool isWithChild)
        {
            var result = UIHelper.GetGridModelFromQueryModel<MaintainQuantity>(
                source,
                query.page,
                query.limit,
                GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel, isWithChild));

            var list = result.Data.Select(item => new
                                                      {
                                                          QuantityID = item.QuantityID,
                                                          OrganizationID = item.OrganizationID,
                                                          Organization = item.Organization.OrganizationName,
                                                          MaintainCode = item.MaintainCode,
                                                          Roadway = item.Roadway,
                                                          BeginStake = item.BeginStake,
                                                          EndStake = item.EndStake,
                                                          CategoryID = item.CategoryID,
                                                          Category = item.MaintainCategory.CategoryName,
                                                          Quantity = item.Quantity,
                                                          Unit = item.MaintainCategory.Unit,
                                                          Price = item.Price,
                                                          Amount = item.Amount,
                                                          CreateDate = item.CreateDate,
                                                          Applicant = item.Applicant,
                                                          ApplicationDate = item.ApplicationDate,
                                                          Auditor = item.Auditor,
                                                          AuditedDate = item.AuditedDate,
                                                          Approver = item.Approver,
                                                          ApprovedDate = item.ApprovedDate,
                                                          State = item.State,
                                                          IsDelay = item.IsDelay,
                                                          Memo = item.Memo,
                                                          item.Comment
                                                      }).ToList();

            return new GridModel<object>()
                       {
                           Aggregates = result.Aggregates,
                           Data = list,
                           Total = result.Total
                       };
        }

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels, bool isWithChild)
        {
            var filterList = new List<IFilterDescriptor>();
            foreach (var item in filterModels)
            {
                if (string.IsNullOrEmpty(item.value))
                    continue;

                if (item.property == "OrganizationID" && isWithChild)
                    continue;

                if (item.property.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase))
                {
                    var targetID = Guid.Parse(item.value);
                    if (targetID != Guid.Empty)
                        filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
                }
                else if (item.property == "ApplicationDate_L") //startData - begin
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "ApplicationDate_H") // startDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else //other filter.
                    filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
            }
            return filterList;
        }

        private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
        {
            //convert the sort description.
            var sortList = new List<SortDescriptor>();
            foreach (var item in sortModels)
            {
                var descriptor = new SortDescriptor()
                {
                    Member = item.property,
                    SortDirection =
                        item.direction.ToLower() == "desc"
                            ? ListSortDirection.Descending
                            : ListSortDirection.Ascending
                };

                if (descriptor.Member == "Organization")
                    descriptor.Member = "Organization.OrganizationName";
                else if (descriptor.Member == "Category")
                    descriptor.Member = "MaintainCategory.CategoryName";

                sortList.Add(descriptor);
            }
            return sortList;

        }


        public static void DeleteMaintainQuantity(Guid id)
        {
            using (var context = new SausageEntities())
            {
                //Delete the Maintain machine
                var machines = context.MaintainMachine.Where(machine => machine.QuantityID == id).ToList();
                foreach (var machine in machines)
                {
                    context.CreateObjectSet<MaintainMachine>().Attach(machine);
                    context.ObjectStateManager.ChangeObjectState(machine, EntityState.Deleted);
                }

                //Delete the Maintain material
                var materials = context.MaintainMaterial.Where(material => material.QuantityID == id).ToList();
                foreach (var material in materials)
                {
                    context.CreateObjectSet<MaintainMaterial>().Attach(material);
                    context.ObjectStateManager.ChangeObjectState(material, EntityState.Deleted);
                }

                //Delete the Maintain labour
                var labourList = context.MaintainLabour.Where(labour => labour.QuantityID == id).ToList();
                foreach (var labour in labourList)
                {
                    context.CreateObjectSet<MaintainLabour>().Attach(labour);
                    context.ObjectStateManager.ChangeObjectState(labour, EntityState.Deleted);
                }

                //Delete the Maintain quantity
                var maintainQuantity = new MaintainQuantity { QuantityID = id };
                context.CreateObjectSet<MaintainQuantity>().Attach(maintainQuantity);
                context.ObjectStateManager.ChangeObjectState(maintainQuantity, EntityState.Deleted);

                context.SaveChanges();
            }
        }

        public static List<MaintainQuantity> GetMaintainQuantityListByDate(DateTime applicationDate)
        {
            using (var context = new SausageEntities())
            {
                return (from item in context.MaintainQuantity.Include("MaintainCategory")
                        where item.OrganizationID == Helper.CurrentPrincipal.Organization.OrganizationID
                              && item.ApplicationDate.Year == applicationDate.Year
                              && item.ApplicationDate.Month == applicationDate.Month
                              && item.ApplicationDate.Day == applicationDate.Day
                        orderby item.MaintainCode descending
                        select item).ToList();
            }
        }

        public static MaintainQuantity GetMaintainQuantityByID(Guid quantityID)
        {
            using (var context = new SausageEntities())
            {
                return
                    context.MaintainQuantity.Include("MaintainCategory").Include("Organization").FirstOrDefault(
                        item => item.QuantityID == quantityID);
            }
        }

        public static List<object> GetSubmittingList()
        {
            using (var context = new SausageEntities())
            {
                //查询养护工作量列表
                var query = from item in context.MaintainQuantity
                            where
                                (item.State == (int) MaintainDataStateEnum.Unsubmit ||
                                 item.State == (int) MaintainDataStateEnum.AuditRejected) &&
                                item.OrganizationID == Helper.CurrentPrincipal.Organization.OrganizationID
                            select new
                                       {
                                           item.QuantityID,
                                           item.MaintainCode,
                                           Organization = item.Organization.OrganizationName,
                                           item.OrganizationID,
                                           item.State,
                                           item.Roadway,
                                           item.BeginStake,
                                           item.EndStake,
                                           item.CategoryID,
                                           Category = item.MaintainCategory.CategoryName,
                                           item.Quantity,
                                           item.MaintainCategory.Unit,
                                           item.Price,
                                           item.Amount,
                                           item.CreateDate,
                                           item.Applicant,
                                           item.ApplicationDate,
                                           item.Auditor,
                                           item.AuditedDate,
                                           item.Approver,
                                           item.ApprovedDate,
                                           item.IsDelay,
                                           item.Memo
                                       };
                return query.ToList<object>();
            }
        }

        public static void UpdateMaintainQuantity(MaintainQuantityListRow data)
        {
            using (var context = new SausageEntities())
            {
                var quantity = context.MaintainQuantity.FirstOrDefault(item => item.QuantityID == data.QuantityID);
                if (quantity == null)
                    return;

                if (quantity.State != (int)MaintainDataStateEnum.Unsubmit && quantity.State != (int)MaintainDataStateEnum.AuditRejected)
                    throw new SausageException(string.Format("养护工程量已经提交，不允许执行编辑操作。"));


                quantity.Roadway = data.Roadway;
                quantity.BeginStake = data.BeginStake;
                quantity.EndStake = data.EndStake;
                quantity.CategoryID = data.CategoryID;
                quantity.Quantity = data.Quantity;
                quantity.Price = data.Price;
                quantity.Amount = data.Quantity * data.Price;
                quantity.Applicant = Helper.CurrentPrincipal.User.UserName;
                quantity.ApplicationDate = data.ApplicationDate;
                quantity.Memo = data.Memo;
                context.SaveChanges();
            }
        }

        public static void UpdateMaintainQuantityState(Guid id, int state)
        {
            using (var context = new SausageEntities())
            {
                var maintainQuantity = context.MaintainQuantity.FirstOrDefault(item => item.QuantityID == id);
                if (maintainQuantity == null)
                    return;

                maintainQuantity.State = state;
                context.SaveChanges();
            }
        }

        public static void CreateMaintainQuantity(MaintainQuantityListRow data)
        {
            using (var context = new SausageEntities())
            {
                var quantity = new MaintainQuantity();
                quantity.QuantityID = Guid.NewGuid();
                quantity.OrganizationID = Helper.CurrentPrincipal.Organization.OrganizationID;
                quantity.MaintainCode = string.Empty;
                quantity.Roadway = data.Roadway;
                quantity.BeginStake = data.BeginStake;
                quantity.EndStake = data.EndStake;
                quantity.CategoryID = data.CategoryID;
                quantity.Quantity = data.Quantity;
                quantity.Price = data.Price;
                quantity.Amount = data.Quantity * data.Price;
                quantity.CreateDate = DateTime.Now;
                quantity.Applicant = Helper.CurrentPrincipal.User.UserName;
                quantity.ApplicationDate = data.ApplicationDate;
                quantity.State = (int)MaintainDataStateEnum.Unsubmit;
                quantity.IsDelay = Helper.IsDelay(data.ApplicationDate);
                quantity.Memo = data.Memo;

                context.AddToMaintainQuantity(quantity);
                context.SaveChanges();

                var targetQuantity =
                    context.MaintainQuantity.FirstOrDefault<MaintainQuantity>(
                        item => item.QuantityID == quantity.QuantityID);
                
                //养管站+日期+路线+养护类型+编号
                targetQuantity.MaintainCode = string.Format("{0}-{1}-{2}-{3}-{4}",
                                                            Helper.CurrentPrincipal.Organization.OrganizationCode,
                                                            data.ApplicationDate.ToString("yyyyMMdd"),
                                                            targetQuantity.Roadway,
                                                            MaintainCategoryHelper.GetMaintainCategoryByID(data.CategoryID).CategoryName,
                                                            targetQuantity.Index);
                context.SaveChanges();
            }
        }

        public static void ExecuteSubmit(Guid[] quantities)
        {
            if (null != quantities && quantities.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

                    foreach (var entity in list)
                    {
                        entity.State = (int)MaintainDataStateEnum.Submitted;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteAudit(Guid[] quantities, bool passed, string comment)
        {
            //判定是否有编号
            if (null != quantities && quantities.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

                    foreach (var maintainQuantity in list)
                    {
                        maintainQuantity.Auditor = Helper.CurrentPrincipal.User.UserName;
                        maintainQuantity.AuditedDate = DateTime.Now;
                        maintainQuantity.Comment = comment;
                        maintainQuantity.State = passed
                                                     ? (int) MaintainDataStateEnum.Audited
                                                     : (int) MaintainDataStateEnum.AuditRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteConfirm(Guid[] quantities, bool passed, string comment)
        {
            //判定是否有编号
            if (null != quantities && quantities.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainQuantity.Where(item => quantities.Contains(item.QuantityID)).ToList();

                    foreach (var maintainQuantity in list)
                    {
                        maintainQuantity.Approver = Helper.CurrentPrincipal.User.UserName;
                        maintainQuantity.ApprovedDate = DateTime.Now;
                        maintainQuantity.Comment = comment;
                        maintainQuantity.State = passed
                                                     ? (int) MaintainDataStateEnum.Confirmed
                                                     : (int) MaintainDataStateEnum.ConfirmationRejected;
                    }
                    context.SaveChanges();
                }
            }
        }
    }
}
